수신 : 연세대학교 보건과학대학 의공학부(김영호 교수)

발신 : 세이프웨어(신환철 대표)

제목 : 추락 및 노인낙상 소스코드(C 언어) 확인 요청

-------------------------------------------------

2.9∼10(2일간) 연세대 방문時 추락·노인낙상 알고리즘을 상세히 설명해 주시고 추락(임계값 기반)·노인낙상(임계값·머신러닝 기반) 소스코드를 제공해 주신 데 감사드립니다.

제공해 주신 임계값 기반 추락 검출 소스코드를 확인해본 결과, 설명해 주신 파이썬 소스코드와는 다르게 C 언어 소스코드에는 △HPF △Signum △상보 필터 등 함수(3개)는 전혀 구현되어 있지 않고 △Jerk △Lag 필터 등 함수(2개)는 미완성 상태(주석 처리)로 포함되어 있으며, △ACC 적분(간소화 버전) △수직가속도 연산 △수직가속도 적분(간소화 버전) 등 함수(3개)만이 구현되어 있는 것으로 판단됩니다(첨부 1 참조).

또한, 임계값 기반 노인낙상 검출 소스코드(C 언어)도 파이썬 소스코드와는 다르게 수직속도 계산 알고리즘이 구현되어 있지 않고 △가속도 △각속도 △Roll·Pitch 등 3가지 지표만을 계산한 후 이를 threshold와 비교하여 노인낙상을 검출하고 있어 초기 개발 버전인 것으로 추정됩니다(첨부 2 참조)

하오니, 귀측이 제공한 소스코드가 최종 버전인지 확인해 주시고, 최종 버전이 아니라면 최종 버전 소스코드를 추가로 제공해 주시기 바라며, 앞으로도 兩 기관이 긴밀히 협력하여 공동 발전을 이루어 나가기를 희망합니다. 끝.

추락 검출 소스코드 비교(파이썬·C 언어)

<첨부 1>

노인낙상 검출 알고리즘 소스코드(C 언어)

<첨부 2>

Acc_ax_tmp = pBuffer1[0] << 8 | pBuffer1[1];

AccData[0] = ((double)(Acc_ax_tmp)/32768*Acc_norm) - OffsetAcc[0];

Acc_ay_tmp = pBuffer1[2] << 8 | pBuffer1[3];

AccData[1] = ((double)(Acc_ay_tmp)/32768*Acc_norm) - OffsetAcc[1];

Acc_az_tmp = pBuffer1[4] << 8 | pBuffer1[5];

AccData[2] = ((double)(Acc_az_tmp)/32768*Acc_norm) - OffsetAcc[2];

Temp_tmp = pBuffer2[0] << 8 | pBuffer2[1];

TempData = (double)(Temp_tmp)/340+36.53;

Gyro_0_tmp = pBuffer3[0] << 8 | pBuffer3[1];

GyroData[0] = (double)(Gyro_0_tmp)/32768*Gyro_norm*Gyro_correc[0][0];

Gyro_1_tmp = pBuffer3[2] << 8 | pBuffer3[3];

GyroData[1] = (double)(Gyro_1_tmp)/32768*Gyro_norm*Gyro_correc[1][1];

Gyro_2_tmp = pBuffer3[4] << 8 | pBuffer3[5];

GyroData[2] = (double)(Gyro_2_tmp)/32768*Gyro_norm*Gyro_correc[2][2];

//10Hz LPF

data[0] = ax_LPF_5hz(AccData[2]); ? ? ? // -z -> x

data[1] = ay_LPF_5hz(AccData[0]); ? ? ? //  x -> y

data[2] = az_LPF_5hz(AccData[1]); ? ? ? // -y -> z

data[3] = gx_LPF_5hz((double)(GyroData[2])*3.14/180);  // -z -> x

data[4] = gy_LPF_5hz((double)(GyroData[0])*3.14/180);  //  x -> y

data[5] = gz_LPF_5hz((double)(GyroData[1])*3.14/180);  // -y -> z

// ACC-GYRO TERM

data[6] = sqrt(data[0]*data[0]+data[1]*data[1]+data[2]*data[2]); // acceleration term

data[7] = sqrt(data[3]*data[3]+data[4]*data[4])*180/3.14;  // gyro term [yaw (x)]

// EULER ANGLE

//acc_angle

data[8] = fabs(atan(data[1]/sqrt(data[0]*data[0]+data[2]*data[2]))); // Roll_acc, phi_a

data[9] = atan(data[0] /sqrt(data[1]*data[1]+data[2]*data[2])); // pitch_acc, theta_a

//gyro_angle

data[12] = data[3] + data[4]*sin(data[14])*tan(data[15]) + data[5]*cos(data[14])* tan(data[15]);  //dotroll

data[13] = data[4]*cos(data[14]) - data[5]*sin(data[14]);  //dotpitch

data[10] = data[14] + 0.01*(data[12] - data[16]); //Roll_gyro (phi)

data[11] = data[15] + 0.01*(data[13] - data[17]); //Pitch_gyro (theta)

data[22] = data[10] - data[8]; //delPhi

data[23] = data[11] - data[9]; //delTheta

data[16] = data[18] + 0.1415*data[22] - 0.1414*data[19]; //p_hat

data[17] = data[20] + 0.1415*data[23] - 0.1414*data[21]; //q_hat

data[18] = data[16]; //prevP = p_hat

data[20] = data[17]; //prevQ = q_hat

data[19] = data[22]; //predelphi = delphi

data[21] = data[23]; //predeltheta = deltheta

data[14] = data[10]; // prevPhi = phi

data[15] = data[11]; // prevTheta = theta;

data[24] = data[10]*180/3.14;

data[25] = data[11]*180/3.14;

//data[26] = fabs(data[24]);

// fall / nonfall ?

if ( (data[6] < 0.82) && (data[7] > 47.3) && ((data[25] < -45) ) ) {

isFall = ENABLE;

State_fall = 1;

}

else {

isFall = DISABLE;

}